home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Freelog Special Edition 10
/
FreelogHS10.iso
/
Buzz
/
Buzz_Advanced_Pack.exe
/
{app}
/
Dev
/
Noise
/
Noise.cpp
next >
Wrap
C/C++ Source or Header
|
2001-08-27
|
7KB
|
399 lines
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include "../../MachineInterface.h"
#include "../../dsplib/dsplib.h"
#pragma optimize ("a", on)
#define MAX_TRACKS 8
#define EGS_ATTACK 0
#define EGS_SUSTAIN 1
#define EGS_RELEASE 2
#define EGS_NONE 3
#define MIN_AMP (0.0001 * (32768.0 / 0x7fffffff))
double const oolog2 = 1.0 / log(2);
CMachineParameter const paraAttack =
{
pt_word, // type
"Attack",
"Attack time in ms", // description
1, // MinValue
0xffff, // MaxValue
0, // NoValue
MPF_STATE, // Flags
16
};
CMachineParameter const paraSustain =
{
pt_word, // type
"Sustain",
"Sustain time in ms", // description
1, // MinValue
0xffff, // MaxValue
0, // NoValue
MPF_STATE, // Flags
16
};
CMachineParameter const paraRelease =
{
pt_word, // type
"Release",
"Release time in ms", // description
1, // MinValue
0xffff, // MaxValue
0, // NoValue
MPF_STATE, // Flags
512
};
CMachineParameter const paraColor =
{
pt_word, // type
"Color",
"Noise color (0=black, 1000=white)", // description
0, // MinValue
0x1000, // MaxValue
0xffff, // NoValue
MPF_STATE, // Flags
0x1000
};
CMachineParameter const paraVolume =
{
pt_byte, // type
"Volume",
"Volume [sustain level] (0=0%, 80=100%, FE=~200%)", // description
0, // MinValue
0xfe, // MaxValue
0xff, // NoValue
MPF_STATE, // Flags
0x80
};
CMachineParameter const paraTrigger =
{
pt_switch, // type
"Trigger",
"Trigger (1=on, 0=off)", // description
-1, // MinValue
-1, // MaxValue
SWITCH_NO, // NoValue
0, // Flags
0
};
CMachineParameter const *pParameters[] = {
// track
¶Attack,
¶Sustain,
¶Release,
¶Color,
¶Volume,
¶Trigger
};
#pragma pack(1)
class tvals
{
public:
word attack;
word sustain;
word release;
word color;
byte volume;
byte trigger;
};
#pragma pack()
CMachineInfo const MacInfo =
{
MT_GENERATOR, // type
MI_VERSION,
0, // flags
1, // min tracks
MAX_TRACKS, // max tracks
0, // numGlobalParameters
6, // numTrackParameters
pParameters,
0,
NULL,
#ifdef _DEBUG
"Jeskola Noise Generator (Debug build)", // name
#else
"Jeskola Noise Generator",
#endif
"Noise", // short name
"Oskari Tammelin", // author
NULL
};
class mi;
class mi;
class CTrack
{
public:
void Tick(tvals const &tv);
void Stop();
void Reset();
void Generate(float *psamples, int numsamples);
void Noise(float *psamples, int numsamples);
int MSToSamples(double const ms);
public:
double Amp;
double AmpStep;
double S1;
double S2;
float Volume;
int Pos;
int Step;
int RandStat;
int EGStage;
int EGCount;
int Attack;
int Sustain;
int Release;
mi *pmi;
};
class mi : public CMachineInterface
{
public:
mi();
virtual ~mi();
virtual void Init(CMachineDataInput * const pi);
virtual void Tick();
virtual bool Work(float *psamples, int numsamples, int const mode);
virtual void SetNumTracks(int const n) { numTracks = n; }
virtual void Stop();
public:
int numTracks;
CTrack Tracks[MAX_TRACKS];
tvals tval[MAX_TRACKS];
};
DLL_EXPORTS
mi::mi()
{
GlobalVals = NULL;
TrackVals = tval;
AttrVals = NULL;
}
mi::~mi()
{
}
inline int CTrack::MSToSamples(double const ms)
{
return (int)(pmi->pMasterInfo->SamplesPerSec * ms * (1.0 / 1000.0));
}
inline double CalcStep(double from, double to, int time)
{
assert(from > 0);
assert(to > 0);
assert(time > 0);
return pow(to / from, 1.0 / time);
}
void CTrack::Reset()
{
EGStage = EGS_NONE;
Attack = MSToSamples(16);
Sustain = MSToSamples(16);
Release = MSToSamples(512);
Pos = 0;
Step = 65536;
Volume = 1.0;
S1 = S2 = 0;
RandStat = 0x16BA2118;
}
void mi::Init(CMachineDataInput * const pi)
{
for (int c = 0; c < MAX_TRACKS; c++)
{
Tracks[c].pmi = this;
Tracks[c].Reset();
}
}
void CTrack::Tick(tvals const &tv)
{
if (tv.attack != paraAttack.NoValue)
Attack = MSToSamples(tv.attack);
if (tv.sustain != paraSustain.NoValue)
Sustain = MSToSamples(tv.sustain);
if (tv.release != paraRelease.NoValue)
Release = MSToSamples(tv.release);
if (tv.color != paraColor.NoValue)
Step = tv.color * 16; // 0..4096 -> 0..65536
if (tv.volume != paraVolume.NoValue)
Volume = (float)(tv.volume * (1.0 / 0x80));
if (tv.trigger != SWITCH_NO)
{
if (Volume > 0)
{
EGStage = EGS_ATTACK;
EGCount = Attack;
Amp = MIN_AMP;
AmpStep = CalcStep(MIN_AMP, Volume * (32768.0 / 0x7fffffff), Attack);
}
}
}
void CTrack::Noise(float *psamples, int numsamples)
{
double amp = Amp;
double const ampstep = AmpStep;
double s1 = S1;
double s2 = S2;
int const step = Step;
int stat = RandStat;
int pos = Pos;
int c = numsamples;
do
{
*psamples++ = (float)(s1 + (s2 - s1) * (pos * 1.0 / 65536.0));
amp *= ampstep;
pos += step;
if (pos & 65536)
{
s1 = s2;
stat = ((stat * 1103515245 + 12345) & 0x7fffffff) - 0x40000000;
s2 = stat * amp;
pos -= 65536;
}
} while(--c);
Pos = pos;
S2 = s2;
S1 = s1;
RandStat = stat;
Amp = amp;
}
void CTrack::Generate(float *psamples, int numsamples)
{
do
{
int const c = __min(EGCount, numsamples);
assert(c > 0);
if (EGStage != EGS_NONE)
Noise(psamples, c);
else
memset(psamples, 0, c * sizeof(float));
numsamples -= c;
psamples += c;
EGCount -= c;
if (!EGCount)
{
switch(++EGStage)
{
case EGS_SUSTAIN:
EGCount = Sustain;
AmpStep = 1.0;
break;
case EGS_RELEASE:
EGCount = Release;
AmpStep = CalcStep(Amp, MIN_AMP, Release);
break;
case EGS_NONE:
EGCount = 0x7fffffff;
break;
}
}
} while(numsamples > 0);
}
void mi::Tick()
{
for (int c = 0; c < numTracks; c++)
Tracks[c].Tick(tval[c]);
}
bool mi::Work(float *psamples, int numsamples, int const)
{
bool gotsomething = false;
for (int c = 0; c < numTracks; c++)
{
if (Tracks[c].EGStage != EGS_NONE)
{
if (!gotsomething)
{
Tracks[c].Generate(psamples, numsamples);
gotsomething = true;
}
else
{
float *paux = pCB->GetAuxBuffer();
Tracks[c].Generate(paux, numsamples);
DSP_Add(psamples, paux, numsamples);
}
}
}
return gotsomething;
}
void CTrack::Stop()
{
EGStage = EGS_NONE;
}
void mi::Stop()
{
for (int c = 0; c < numTracks; c++)
Tracks[c].Stop();
}